FreeBSD 13 NFS exports man(5) page 2021 中文译本
Table of Contents
1. 译者总注
1.1. 关于此译本
李守中是开源软件理念坚定的支持者,所以译本虽不是软件,但依旧仿照开源软件的协议发布:
- 无担保:本文作者不保证作品内容准确无误,亦不承担任何由于使用此文档所导致的损失。
- 自由使用:任何人都可以自由地 阅读/链接/打印 此文档,无需任何附加条件。
- 名誉权:任何人都可以自由地 转载/引用/再创作 此文档,但必须保留作者署名并注明出处。
如果读者发现作品中有错误的地方,劳请来信指出。任何提高作品质量的建议李守中都将虚心接纳。
1.2. 原文档来源
本文档根据 FreeBSD 13.2 NFS exports manpage (man 5 exports
) 翻译。
1.3. 译者的话
对于直译后无法准确描述软件行为的句子,李守中会根据软件行为对这些句子进行意译。
对于必须添加很多内容才能实现意译的句子,李守中会尽量用直译 + 译者注 的方式来翻译。
受限于李守中的中文水平,在对句子进行意译时可能会偏离作者的本意,请读者谨慎参考。
有能力的读者可以从此链接 FreeBSD_13_NFS_exports_man(5)_page_2021.txt 下载英文原文与本文做对照。
PS: 从遣词造句的混乱程度和排版的随意性来看,这篇文档的作者和 man 4 nfsv4
的作者应该是同一个人...
2. 名称
exports -- 为 NFS mount 请求定义远程挂载点
3. 摘要
exports
4. 描述
exports 根据 NFS server 规范,为 NFS 挂载协议指定了远程挂载点。详情可见 Network File System Protocol Specification, RFC1094, Appendix A and NFS: Network File System Version 3 Specification, Appendix I。
文件中的每一行 (除了以井号 # 开头的注释行) 为一个或多个 host 指定了一个本地 server 上的文件系统或者 NFSv4 树根节点的挂载点和导出配置。一个长的配置行可以通过在除最后一行之外的行的行尾加入反斜杠 (\) 被分成多行。对于 server 上的每个本地文件或 NFSv4 树根节点,只能指定一次主机,并且每个 server 文件系统可能只有一个默认条目,适用于所有其他主机。后者将文件系统导出到全局,仅当文件系统包含公共信息时才应这样使用。
译者注: 注意上面这段说的「每个 NFSv4 树的根节点只能被导出一次」。NFSv4 树的根节点是任意文件系统的挂载点。这就意味着「一旦文件系统中的某个路径被导出了,那么整个文件系统都被导出了」。举例来说,有路径 /storage0/apps/app1,其中 storage0 是 zpool 的根的挂载点,apps 是 storage0 的一个 dataset,app1 是 dataset 中的一个目录。那么,如果在 /etc/exports 中写导出 /storage0/apps/app1 的配置,那么实际上 /storage0/apps 这个 dataset 整个都被导出了。有权限的用户可以挂载 /storage0/apps 中的任意路径,而不仅限于 /storage0/apps/app1。
译者注: 一定要理解上面那段译者注。FreeBSD 上 NFS server 的行为和 Linux 上的 NFS server 的行为并不相同。如果直接把使用 Linux 上的 NFS server 的经验迁移到 FreeBSD 上会带来严重的安全隐患。
译者注: 配置行由 <dir-path> <option> <host-set> 三个字段组成。
在一个挂载实例中,第一个字段 (<dir-path>) 指定了 server 上的可以被相关 client 挂载的文件系统中的目录的路径。这个规范有三种格式。第一种格式是将所有挂载点目录列为以空格分隔的绝对路径。这个绝对路径列表应该被考虑作为 "administrative control" 因为它只由 mountd(8) 守护进程强制执行而不是内核。因此,它只适用于 NFSv2 和 NFSv3 挂载,并且只适用于 client 对 mount 协议的使用。第二种格式是指定文件系统根目录的路径,后跟 -alldirs
标志;这个格式允许 host 挂载这个文件系统下的任何目录,如果 mountd 使用了 -r
参数的话还允许挂载这个文件系统下的任何文件。因为 NFSv4 不使用 mount 协议,"administrative contols" 不会被应用并且在这个文件系统下的所有目录都可以通过 NFSv4 挂载,即使 -alldirs
参数没有被指定。第三种格式是使用 V4:
开头,后跟绝对路径来指定 NFSv4 树根节点。以 V4:
开头的行不导出任何文件系统,这行配置仅仅是为使用 NFSv4 的 client 标记了 server 上的目录树的根节点。以 NFSv4 协议导出文件系统的配置在 exports 文件中的写法与以 v2 v3 协议导出文件系统的语法相同。路径名不能包含符号链接,不能出现 .
和 ..
这种表示相对路径的符号。文件系统的挂载点可能出现在多行中,每一行都有不同的主机集和导出选项。
译者注: <dir-path> 这个字段指定了要被导出的目录,这第一个字段有三种格式。第一种是以空格分隔多个绝对路径以达到用一行配置导出多个路径的效果。但由于只有 mountd(8) 允许在第一个字段内指定多个目录,所以只有使用 mount protocol (由 mountd(8) 实现) 的 NFS v2 和 v3 可以使用这种格式。
译者注: <dir-path> 字段的第二种格式是指定根路径,然后添加 -alldirs
参数,这个参数允许 client 挂载根目录下的任何目录,如果 server 上的 mountd 进程在启动时还指定了 -r
参数,那么 client 还可以挂载指定目录下的任何文件。对于 NFSv4 来说,它不使用 mount protocol 而是在协议内部实现了自定义的挂载协议。这意味着 mountd 程序在只开启 NFSv4 协议的情况下没有用 (只使用 NFSv4 时可以不启动 mountd 进程),而 -alldirs
参数是作用于 mountd 进程的,所以不论加不加 -alldirs
参数,使用 NFSv4 的 client 都可以挂载 server 导出的路径下的任意目录。
译者注: <dir-path> 的第三种格式是让配置行以 V4:
开头,后面和普通的导出配置没有区别。但是以 V4:
开头的行并不导出任何目录,而是指定了 NFSv4 树的根节点。关于更多的 V4:
行的信息可以看 FreeBSD 13 NFSv4 man(4) page 2019 中文译本.org 。
译者注: 配置行由 <dir-path> <option> <host-set> 三个字段组成。
第二个字段 (<option>) 指定了文件系统如何被导出到主机集。可选的配置项指定了被导出的文件系统是只读的还是可以被读写的,以及 client 的 UID 如何被映射到 server 的用户身份。对于 NFSv4 根节点来说,可以被指定的选项只有与安全相关的参数: -sec
, -tls
, tlscert
和 -tlscertuser
。
译者注: 配置行的第二个字段指定了被导出的目录的行为。而对于以 V4:
开头的行来说,只有上面提到的几个与安全相关的参数可以用。
导出参数有:
- -maproot=user
client 以 root 用户挂载目录时,将 root 身份限制为指定的身份。
<user>
字段指定的用户包含用户本身与其所在的所有的 server 上的组 (见 id(1))。用户名和组名可以用字符串或者 UID 和 GID 来表示。遇到有空格的可以加引号,或者用反斜杠转义空格。- -maproot=user:group1:group2:...
client 以 root 用户挂载目录时,这个用冒号分隔的列表指定了 root 身份被限定到的精确的身份。列表内的值可以是字符串也可以是 UID/GID。需要注意,
user:
应该用于区分不包含组的凭据与该用户的完整凭据。组名字符串有空格时可以加冒号,或者用反斜杠转义空格。 译者注: 第三句话想说的意思是-maproot=lsz:
和-maproot=lsz
不是一个东西,前者只使用 lsz 用户的身份,而后者还可以使用 lsz 所属的组作为身份。详见本站的 FreeBSD 上的 NFS 一文。- -mapall=user 或 -mapall=user:group1:group2:...
不论 client 使用什么 UID/GID,其权限都变为参数指定的用户与用户组,包括 root。语法与
-maproot
相同。
选项 -r
是 -maproot
的同义词,旨在向后兼容旧的 exports 文件。
不指定 -maproot
和 -mapall
情况下,client 使用 root 用户挂载目录,root 用户的身份会被压缩为 65534:65533 (nobody:nogroup)。client 上的其他用户不受影响,依旧会被映射为 server 上的对应用户。如果指定了 -maproot
参数,那么 client 使用 root 用户远程挂载目录后,root 用户的身份会被压缩为 -maproot
参数指定的身份。如果指定了 -mapall
参数,则不论 client 使用什么身份挂载文件,其身份都会变成 -mapall
参数指定的身份。
- -sec=flavor1:flavor2...
冒号分隔的列表指定了身份认证方式的偏好。可选的 flavors 有
sys
,krb5
,krb5i
和krb5p
共 4 个。如果指定了多个身份认证方式,排在左边的有更高的优先级。如果 server 不支持任何参数中指定的认证方式,那么就使用默认的认证方式sys
。- -ro
指定了文件系统应该被 client 以只读的方式挂载 (默认是可读可写)。选项
-o
和-ro
是同义词,旨在向后兼容旧的 exports 文件。
可以使用 -public
选项来严格按照规范 (RFC 2054 和 RFC 2055) 导出 WebNFS。然而,这个选项本身允许对所有被导出的目录下的文件读写,不要求使用保留端口,也不需要 UID 映射。提供这个选项只是为了符合规范,通常不应使用。对于使用 WebNFS 导出的目录来说,使用 -webnfs
参数更合适,这个参数相当于组合使用 -public -mapall=nobody -ro
三个参数。需要注意,一台 server 上被 WebNFS 导出的目录只能有一个。
- -index=<file>
选项可用于指定一个文件,如果使用公共文件句柄 (WebNFS) 查找目录,将返回其句柄。这是为了模仿 URL 的行为。 如果没有指定
-index
选项,目录文件句柄将照常返回。-index
选项仅在与-public
或-webnfs
选项结合使用时才有意义。
-tls
, -tlscert
和 -tlscertuser
选项用于要求 client 根据 RFC NNNN 在 NFS 数据传输时用 TLS 加密。为了让 NFS 挂载可以支持 TLS,必须在 server 上运行 rpc.tlsservd(8) 进程。
-tls
选项要求 client 必须使用 TLS-tlscert
选项要求 client 使用 TLC 并在 TLS 握手阶段提供一个可以验证的 X.509 证书-tlscertuser
选项要求 client 使用 TLS 并在 TLS 握手阶段提供一个可以验证的 X.509 证书。证书的 subjAltName 的 otherName 组件必须有一个 OID 1.3.6.1.4.1.2238.1.1.1 和一个格式为 "user@domain" 的 UTF8 字符串。 "user@domain" 将以与 nfsuserd(8) 相同的方式转换为指定用户的凭据,其中 "user" 通常是用户名,是 server 的密码数据库,"domain" 是服务器的 DNS 域名。
当这三个参数都没有被使用,在 NFS 中允许但不必须使用 TLS。
- -quiet
NFS 在 /etc/exports 文件中检测到异常的行配置时,不会输出日志到系统日志中。这在要屏蔽一些已知问题的提示时很有用。(见后文的 例子 一节)
译者注: 配置行由 <dir-path> <option> <host-set> 三个字段组成。
第三个字段 (<host-set>) 是这些配置要应用到的主机集。这个集合可以三种形式给出。第一种形式是列出主机名列表,列表项用空格分开。(可以使用 Standard Internet "dot" 地址代替主机名) 第二种形式是指定定义在 netgroup 文件中的 "netgroup"。(详见 netgroup(5)) 第三种形式是使用 IP 和子网掩码的方式指定一整个网段中的主机。第三种方法需要的资源开销比较小,建议用于要应用于大量客户端的配置行中。
第三个字段可以使用的前两种形式需要列出以空格分隔的名称列表。所有的列表中的名称都会被检查其是否属于某个 netgroup 或者是某个主机的主机名。使用主机的 FQDN 通常可以避免主机与网络组同名的问题。第三种形式使用 -network=netname[/prefixlength]
和可选选项 -mask=netmask
来指定主机组。子网掩码可以写在 -network
选项里也可以使用 -mask
选项单独指定。如果子网掩码没有以任何方式指定,子网掩码的默认值将是网络类(A, B 或 C, 参阅 inet(4)) 的历史掩码。此用法已弃用,并输出告警日志。见后文的 例子 一节。
范围内的 IPv6 地址必须携带范围标识符,如 inet6(4) 中所述。 例如,"fe80::%re2/10" 用于在 re2 接口上指定 fe80::/10。
译者注: 配置行由 <dir-path> <option> <host-set> 三个字段组成。
前文提到的配置行的第一个字段 (<dir-path>) 的第三种格式 (以 V4: 开头的配置行) 中的目录路径指明了 NFSv4 树的根节点。每一个 server 只能有一个 NFSv4 树的根节点。因此,所有的以 V4: 开头的行必须使用相同的路径配置。对于 ZFS 之外的文件系统来说,这个路径的位置可以是任何目录,并且这个路径不必在一个被导出的文件系统中。如果这个路径不在被导出的文件系统中,那么 client 挂载这个路径之后只能执行操作的有限子集,这样 NFSv4 client 就可以遍历这个树以找到所有被导出的文件系统。尽管部分 NFSv4 树可以不导出,但整个 NFSv4 树必须包含能够通过 NFS 导出的本地文件系统。必须导出 NFSv4 树的子树中的所有 ZFS 文件系统。NFSv4 不使用 mount protocol 并且允许 client 跨越 server 挂载点边界,尽管并非所有 client 都能够跨越挂载点。
译者注: 就是以 V4:
开头的配置行里面指明的路径是 NFSv4 树的根路径,NFSv4 树在每个 server 上只能有一棵。也就是说,以 V4: 开头的行可以有多个,但是这多个行必须使用相同的路径配置。多行 V4: 配置可以为不同的主机集指定不同的参数。
译者注: 对于非 ZFS 的文件系统来说,这个路径位置可以任选,并且不必为这个路径单独添加一个不带 V4: 开头的导出配置。对于 ZFS 文件系统来说,ZFS Volume 下面如果还挂在了 ZFS Volume 那么必须为每一个 Volume 写一个配置才能导出整个父级 Volume。
译者注: 给一个例子方便理解这个跨越挂载点边界的含义。现有 /mnt/tmp1 目录被导出,该目录下有两个子目录 /mnt/tmp1/tmp11 和 /mnt/tmp1/tmp12,其中 /mnt/tmp1/tmp12 是 /dev/da0p2 的挂载点。client 挂载 /mnt/tmp1 目录之后可以正常看到 /mnt/tmp1/tmp11 这个目录,但是如果 client 不能跨越挂载点就看不到 /mnt/tmp1/tmp12 这个目录。
配置行中的 -sec
选项指定哪些安全类型可用于不使用文件句柄的 NFSv4。由于这些操作 (SetClientID、tClientIDConfirm、Renew、DelegPurge 和 ReleaseLockOnwer) 在 server 中分配/修改状态,因此可以通过此选项限制某些客户端使用 krb5[ip] 安全类型。 见后文的 例子 一节。第三种形式对 NFSv2 和 NFSv3 没有意义,因此被忽略。
可以通过向 mountd(8) 程序发送 HUP 信号来重读 exports 文件:
/etc/rc.d/mountd onereload
在向 mountd 发送 HUP 信号之后,可以查看 syslogd(8) 来检查 mountd 的日志以判断 exports 文件中是否有错误。
5. 文件
/etc/exports 默认的用于指定要被导出的目录的文件
6. 例子
/usr /usr/local -maproot=0:10 friends /usr -maproot=daemon grumpy.cis.uoguelph.ca 131.104.48.16 /usr -ro -mapall=nobody /u -maproot=bin: -network 131.104.48 -mask 255.255.255.0 /a -network 192.168.0/24 /a -network 3ffe:1ce1:1:fe80::/64 /u2 -maproot=root friends /u2 -alldirs -network cis-net -mask cis-mask /cdrom -alldirs,quiet,ro -network 192.168.33.0 -mask 255.255.255.0 /private -sec=krb5i /secret -sec=krb5p V4: / -sec=krb5:krb5i:krb5p -network 131.104.48 -mask 255.255.255.0 V4: / -sec=sys:krb5:krb5i:krb5p grumpy.cis.uoguelph.ca
上面提到的 /usr
, /u
, /a
和 /u2
都是本地文件系统的挂载点,上面的例子指定了:
第一行表示以 /usr
目录为根的文件系统被导出供 friends
主机使用。 friends
主机定义在 netgroup 文件里。client 上的 root 用户被映射到 server 上的 UID 为 0 的用户及其所属组,或 GID 10 为 10 的组。 /usr
目录以可读写的方式被导出。 friends
主机除了可以挂载 /usr
之外还可以挂载 /usr/local
。第二行表示 /usr
目录还可以被 grumpy.cis.uoguelph.ca
和 131.104.48.16
挂载,这两台主机以 root 身份挂载 /usr
目录时使用 server 主机上的 daemon
用户的身份 (用户和所属组)。第三行表示 /usr
目录以只读的方式被导出,任何主机都可以挂载,任何主机挂载该目录时,使用 server 上的 bonody
用户的身份 (用户和所属组)。
第四行表示以 /u
目录为根的文件系统被导出,所有 131.104.48.0/24 网段内的主机都可以挂在该目录。这些主机在以 root 身份挂载该目录时,使用 server 上的 bin
用户的身份,使用 bin
用户所在的组作为身份。
第五行表示以 /a
目录为根的文件系统被导出,所有 192.168.0.0/24 网段内的主机都可以挂载该目录。这里没有使用 -mask
选项指定主机的子网掩码而是直接在 -network
选项的值中指定了子网掩码。
第六行表示以 /a
目录为根的文件系统被导出,所有 3ffe:1ce1:1:fe80::/64 网段内的主机都可以挂载该目录。需要注意,与 IPv4 地址不同,IPv6 地址必须写全。此外,在使用 IPv6 地址时,不能使用 -mask
选项。
第七行表示以 /u2
目录为根的文件系统被导出, friends
主机可以挂载该目录。 friends
使用 root 身份挂载 /u2
目录时,root 用户的身份不会被改变。
第八行表示以 /u2
目录为根的文件系统被导出,定义在 netgroup 文件里的 cis-net 网段的主机可以挂载该目录以及该目录下的所有子目录。
第九行表示以 /cdrom
目录为根的文件系统被以制度的方式导出。所有 192.168.33.0/24 网段内的主机都可以挂载该目录及其所有子目录。由于 /cdrom 是 CD-ROM 设备的常规挂载点,如果当前没有 CD-ROM 介质被挂载,则此导出将失败,因为 -alldirs
选项会导出根文件系统的子目录。 -quiet
选项表示不向 syslog 输出 error 日志。一旦挂载了实际的 CD-ROM,mount(8) 就会通知 mountd(8),并且 /cdrom 文件系统将按预期导出。 注意,如果不使用 -alldirs
选项,也能正常导出。虽然 /cdrom 下没有安装 CD-ROM 介质,但它会导出作为空目录的 /cdrom。
译者注: /cdrom 目录在没有挂载任何的 CD-ROM 设备或者文件,但是依旧被导出的情况下,被导出的是一个空目录。此时可以等效成导出了一个空目录,client 挂载什么的一切正常。上一段说的失败指的是,CD-ROM 被挂载后,client 通常真正要挂载的是 /cdrom 目录下的东西,此时该目录为空,没有东西可以挂在,所以才说导出失败。一旦 CD-ROM 被挂载后,/cdrom 目录的预期行为就恢复正常了。
第十行表示以 /private
为根目录的文件系统被导出。使用 Kerberos 5 验证 client 身份,并且所有访问都需要保护消息完整性。
第十一行表示以 /secret
为根目录的文件系统被导出。使用 Kerberos 5 身份验证 client 身份,并且 client 访问它产生的所有数据都被加密。
第十二行表示,NFSv4 树以 /
为根目录,只要提供有效的 Kerberos 凭据, 131.104.48.0/24
子网内的任何客户端都能在 server 执行 NFSv4 状态操作。
第十三行表示,在以 /
为根的 NFSv4 树上,允许机器 grumpy.cis.uoguelph.ca
使用 AUTH_SYS
凭据以及 Kerberos 凭据在服务器上执行 NFSv4 状态操作。
下面是同时被 NFSv3 和 NFSv4 导出的目录的配置的例子:
V4: /wingsdl/nfsv4 /wingsdl/nfsv4/usr-ports -maproot=root -network 172.16.0.0 -mask 255.255.0.0 /wingsdl/nfsv4/clasper -maproot=root clasper
一个 V4: 行用来声明 NFSv4 的根目录。其他行使用 /etc/exports 中给出的绝对路径声明特定的导出目录。
导出目录的路径用于 v3 和 v4。但是,对于 v3 和 v4,它们的解释不同。使用 NFSv3 时,client 挂载 usr-ports 目录的命令是:
mount server:/wingsdl/nfsv4/usr-ports /mnt/tmp
使用 NFSv4 挂载时要以 V4: 行指定的目录为跟目录:
mount server:/usr-ports /mnt/tmp
译者注: 可以不用加 -o nfsv4
,因为 NFS client 会自动与 server 从高版本向低版本协商使用的协议。
如果 client 同时支持了 v3 和 v4 两个 NFS 版本,挂载路径的不同写法也可以用来区分 client 使用的 NFS 版本。使用完整的绝对路径对应 v3 挂载,使用 V4: 行指定的路径为根路径对应着 v4 挂载。
需要注意,NFSv3 和 NFSv4 的挂载行为不同。client 没有要挂载的目录的权限时,使用 NFSv4 可以正常挂载,但是之后读/写访问将失败。而 NFSv3 拒绝挂载请求。
7. 更多内容
nfsv4(4), netgroup(5), mountd(8), nfsd(8), rpc.tlsservd(8), showmount(8)
8. 标准
功能的实现基于这些标准: Network File System Protocol Specification, Appendix A, RFC 1094 NFS: Network File System Version 3, Appendix I, RFC 1813 Towards Remote Procedure Call Encryption By Default, RFC nnnn.
9. BUGS
export option 被关联到内核中的本地挂载点,并且对于本地 server 上的挂载点下的任何被导出子目录都不能有矛盾的配置。建议将 server 上 exports 文件中的配置行按被导出的目录排序。主机名和 netgroup 的名称不能冲突,在指定主机时使用 FQDN 通常可以避免与 netgroup 名称冲突的问题。
译者注: 当一个目录被导出多次以针对不同的 client 使用不同的导出参数时,这些配置参数不能有冲突。比如,导出的目录和只读的和可读写的。
FreeBSD 13.0 2021.09.11